Últimas Músicas

Programação

Locutores

Top 10 Músicas

Top Vídeos

Notícias

Cover
Carregando...
Web Rádio Old Music Six Seven

Sobre Nos

Web Rádio Old Music Six Seven

"Feche os olhos e deixe a memória voar. Aquela canção, aquele momento... tudo de volta para você. Web Rádio Old Music 67: música com alma, som com história."

<p><span style="color: rgb(0, 0, 0);">Dos grandes clássicos ao som que marcou gerações! A sua melhor companhia em qualquer lugar. Web Rádio Old Music Six Seven! Aumente o som, a nostalgia começou."</span></p>

Politica de Privacidade

1. Coleta de Dados

O aplicativo Web Rádio Old Music Six Seven coleta apenas informações necessárias para o funcionamento do serviço, como nome de usuário para o chat e endereço IP para controle de spam.

2. Uso das Informações

As informações coletadas são utilizadas exclusivamente para:

- Permitir interação no chat e envio de recados
- Controle de spam e segurança
- Melhoria da experiência do usuário

3. Compartilhamento

Não compartilhamos suas informações pessoais com terceiros, exceto quando exigido por lei.

4. Armazenamento

Seus dados são armazenados de forma segura em nossos servidores e são mantidos apenas pelo tempo necessário.

5. Seus Direitos

Você pode solicitar a remoção de seus dados a qualquer momento entrando em contato conosco.

6. Contato

Para dúvidas sobre privacidade, entre em contato através dos nossos canais oficiais.

Contato

Web Rádio Old Music Six Seven

, ", <, etc — vetor de XSS via tenant config). const CONFIG = { hash: "09d6a53ea304e896f651612ad756400a", apiBase: "https:\/\/app.player-webservic.com\/site1\/ajax", azuracastUrl: "https:\/\/s09.w3bserver.com", stationId: "webrdiooldmusicsixseven_09d6a5", streamUrl: "https:\/\/s09.w3bserver.com\/listen\/webrdiooldmusicsixseven_09d6a5\/radio.mp3", radioName: "Web R\u00e1dio Old Music Six Seven", whatsapp: "14991521374", rssUrl: "", noticiasFontes: {"brasil":"https:\/\/news.google.com\/rss?hl=pt-BR&gl=BR&ceid=BR:pt"}, modoNoticias: 'automatica', noticiasLimite: 6, blogLimite: 6, exibirMusica: true, exibirOuvintes: false, ouvintesSimulados: false, logoUrl: "https:\/\/app.player-webservic.com\/radio-dashboard\/model1\/uploads\/sites\/09d6a53ea304e896f651612ad756400a\/site_logo_1779391929.jpg", updateInterval: 10000, chatInterval: 5000, // AdSense Config adsense: { publisherId: "", autoAds: false, slotInfeed: "", slotInarticle: "" }, // Programacao Config modoProgramacao: "automatica", programacaoTexto: "", // Base URL para assets (uploads, etc) baseUrl: "https:\/\/app.player-webservic.com\/site1", // Fuso horário da rádio timezone: "America\/Sao_Paulo", features: {} }; // ==================== ACCENT CONTRAST GUARD ==================== // Garante que --accent (extraido da capa) tenha contraste minimo contra // --bg-primary. Mantem hue/saturation, ajusta lightness via HSL ate // atingir WCAG ratio 3.5+ (UI nao-textual). Reage a troca de tema. window.PWS_ensureAccentContrast = (function() { function srgbToLin(c) { const v = c / 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); } function relLum(r, g, b) { return 0.2126 * srgbToLin(r) + 0.7152 * srgbToLin(g) + 0.0722 * srgbToLin(b); } function contrastRatio(L1, L2) { const a = Math.max(L1, L2), b = Math.min(L1, L2); return (a + 0.05) / (b + 0.05); } function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b); let h = 0, s = 0, l = (max + min) / 2; if (max !== min) { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return [h, s, l]; } function hslToRgb(h, s, l) { let r, g, b; if (s === 0) { r = g = b = l; } else { const hue2rgb = (p, q, t) => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1/6) return p + (q - p) * 6 * t; if (t < 1/2) return q; if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3); } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } function parseBg() { const cs = getComputedStyle(document.documentElement); const bg = (cs.getPropertyValue('--bg-primary') || '').trim(); let m; if ((m = bg.match(/rgba?\(\s*(\d+)[\s,]+(\d+)[\s,]+(\d+)/))) return [+m[1], +m[2], +m[3]]; if ((m = bg.match(/^#([0-9a-f]{6})$/i))) { return [parseInt(m[1].slice(0,2),16), parseInt(m[1].slice(2,4),16), parseInt(m[1].slice(4,6),16)]; } if ((m = bg.match(/^#([0-9a-f]{3})$/i))) { return [parseInt(m[1][0]+m[1][0],16), parseInt(m[1][1]+m[1][1],16), parseInt(m[1][2]+m[1][2],16)]; } return [15, 15, 15]; } return function ensureAccentContrast(r, g, b, opts) { opts = opts || {}; const minRatio = opts.minRatio || 3.5; const minSat = opts.minSat != null ? opts.minSat : 0.35; const bg = opts.bg || parseBg(); const bgLum = relLum(bg[0], bg[1], bg[2]); const direction = bgLum < 0.18 ? +1 : -1; let [h, s, l] = rgbToHsl(r, g, b); if (s < minSat) s = minSat; let cur = hslToRgb(h, s, l); let ratio = contrastRatio(relLum(cur[0], cur[1], cur[2]), bgLum); let attempts = 0; while (ratio < minRatio && attempts < 40) { l += direction * 0.035; if (l > 0.92) { l = 0.92; if (direction > 0) break; } if (l < 0.10) { l = 0.10; if (direction < 0) break; } cur = hslToRgb(h, s, l); ratio = contrastRatio(relLum(cur[0], cur[1], cur[2]), bgLum); attempts++; } return cur; }; })(); // Aplica accent dinamico, calcula --accent-on (texto sobre o accent) // por luminancia e guarda o RGB cru pra reaplicar quando o tema mudar. window._pwsAccentSource = null; function pwsApplyAccentVars(adjRgb) { const [r, g, b] = adjRgb; document.documentElement.style.setProperty('--accent', `rgb(${r},${g},${b})`); document.documentElement.style.setProperty('--accent-rgb', `${r},${g},${b}`); const srgb = c => { const v = c / 255; return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); }; const lum = 0.2126 * srgb(r) + 0.7152 * srgb(g) + 0.0722 * srgb(b); document.documentElement.style.setProperty('--accent-on', lum > 0.55 ? '#1a1a1a' : '#ffffff'); } window.applyDynamicAccent = function(r, g, b) { window._pwsAccentSource = [r, g, b]; pwsApplyAccentVars(window.PWS_ensureAccentContrast(r, g, b)); }; if (typeof MutationObserver !== 'undefined') { const _themeObs = new MutationObserver(() => { if (window._pwsAccentSource) { const [r, g, b] = window._pwsAccentSource; pwsApplyAccentVars(window.PWS_ensureAccentContrast(r, g, b)); } }); _themeObs.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] }); } // Carrega flags das Automacoes IA. Usa classe no body pra mostrar/ocultar // botoes "info do artista" sem precisar re-renderizar nada. async function loadFeatures() { try { const res = await fetch(`${CONFIG.apiBase}/site_features.php?hash=${CONFIG.hash}`); const data = await res.json(); if (data && data.success && data.features) { CONFIG.features = data.features; if (data.features.ai_artist_modal) document.body.classList.add('ai-artist-on'); } } catch (e) { /* falha silenciosa: features ficam off */ } } const state = { isPlaying: false, volume: 80, mounts: [], currentMount: null, activeMountIdx: 0, songElapsed: 0, songDuration: 0, songStartTime: 0, progressInterval: null, miniPlayerClosed: false }; // HLS helpers (hls.js ja carregado no head) let _wsHls = null; const wsLoadHlsLib = () => { if (window.Hls) return Promise.resolve(window.Hls); return new Promise((resolve, reject) => { const s = document.createElement('script'); s.src = 'https://cdn.jsdelivr.net/npm/hls.js@latest'; s.onload = () => resolve(window.Hls); s.onerror = reject; document.head.appendChild(s); }); }; const wsIsHls = (u, m) => (m && (m.format === 'HLS' || m.is_hls)) || /\.m3u8(\?|$)/i.test(u || ''); const wsDetachHls = () => { if (_wsHls) { try { _wsHls.destroy(); } catch(e){} _wsHls = null; } }; // Elements const $ = (sel) => document.querySelector(sel); const $$ = (sel) => document.querySelectorAll(sel); const els = { audio: $('#audio-player'), playBtn: $('#btn-play'), miniPlayBtn: $('#mini-play'), volumeSlider: $('#volume-slider'), miniVolumeSlider: $('#mini-volume'), volumeIcon: $('#volume-icon'), volumeValue: $('#volume-value'), coverArt: $('#cover-art'), miniCover: $('#mini-cover'), coverWrapper: $('.cover-wrapper'), progressRing: $('#progress-ring'), songTitle: $('#song-title'), miniTitle: $('#mini-title'), songArtist: $('#song-artist'), miniArtist: $('#mini-artist'), qualitySelector: $('#quality-selector'), miniQualitySelector: $('#mini-quality-selector'), visualizer: $('#visualizer'), miniPlayer: $('#mini-player'), playerCard: $('.player-card'), listeners: $('#listeners span'), likeCount: $('#like-count'), dislikeCount: $('#dislike-count'), historyGrid: $('#history-grid'), djGrid: $('#dj-grid'), topList: $('#top-list'), newsGrid: $('#news-grid'), chatMessages: $('#chat-messages'), toast: $('#toast') }; // Utils const utils = { toastTimeout: null, toast(msg, type = 'info', duration = 3000) { const toast = els.toast; const icon = toast.querySelector('.toast__icon i'); const title = toast.querySelector('.toast__title'); const message = toast.querySelector('.toast__message'); const progressBar = toast.querySelector('.toast__progress-bar'); // Configurar icone e titulo baseado no tipo const configs = { success: { icon: 'fa-check', title: 'Sucesso!' }, error: { icon: 'fa-times', title: 'Erro!' }, info: { icon: 'fa-info', title: 'Informacao' }, warning: { icon: 'fa-exclamation', title: 'Atencao!' } }; const config = configs[type] || configs.info; icon.className = `fas ${config.icon}`; title.textContent = config.title; message.textContent = msg; // Reiniciar animacao da barra de progresso progressBar.style.animation = 'none'; progressBar.offsetHeight; // Trigger reflow progressBar.style.animation = `toast-progress ${duration / 1000}s linear forwards`; // Mostrar toast toast.className = `toast visible toast--${type}`; // Limpar timeout anterior if (this.toastTimeout) clearTimeout(this.toastTimeout); // Auto-hide this.toastTimeout = setTimeout(() => toast.classList.remove('visible'), duration); }, escape(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; }, formatTime(ts) { return new Date(ts).toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }); }, // Create AdSense ad unit dynamically createAdUnit(slotId, format = 'auto', style = 'display:block') { if (!CONFIG.adsense.publisherId || !slotId) return ''; return `
`; }, // Initialize AdSense ads added dynamically initDynamicAds() { if (CONFIG.adsense.autoAds) return; if (typeof adsbygoogle !== 'undefined') { document.querySelectorAll('.adsense-container--dynamic ins.adsbygoogle:not([data-adsbygoogle-status])').forEach(() => { try { (adsbygoogle = window.adsbygoogle || []).push({}); } catch(e) {} }); } } }; // Player const player = { init() { this.bindEvents(); this.loadMounts(); this.updateNowPlaying(); setInterval(() => this.updateNowPlaying(), CONFIG.updateInterval); this.setupScrollDetection(); this.startProgressUpdate(); }, startProgressUpdate() { // Atualizar progresso a cada segundo state.progressInterval = setInterval(() => { if (state.songDuration > 0 && state.songStartTime > 0) { const now = Date.now() / 1000; const elapsed = now - state.songStartTime; const progress = Math.min(elapsed / state.songDuration, 1); this.updateProgressRing(progress); } }, 1000); }, updateProgressRing(progress) { const ring = els.progressRing; if (!ring) return; const r = 49; const circumference = 2 * Math.PI * r; // r=49 const offset = circumference * (1 - progress); ring.style.strokeDashoffset = offset; // Sync glow layer const glow = document.getElementById('progress-ring-glow'); if (glow) glow.style.strokeDashoffset = offset; }, bindEvents() { els.playBtn.onclick = () => this.toggle(); els.miniPlayBtn.onclick = () => this.toggle(); // Fechar mini player $('#mini-player-close').onclick = () => { els.miniPlayer.classList.remove('visible'); state.miniPlayerClosed = true; }; els.volumeSlider.oninput = (e) => this.setVolume(e.target.value); els.miniVolumeSlider.oninput = (e) => this.setVolume(e.target.value); els.volumeIcon.onclick = () => this.toggleMute(); $('#btn-like').onclick = () => this.vote('like'); $('#btn-dislike').onclick = () => this.vote('dislike'); $('#mini-like').onclick = () => this.vote('like'); $('#mini-dislike').onclick = () => this.vote('dislike'); els.audio.onplaying = () => this.onPlay(); els.audio.onpause = () => this.onPause(); els.audio.onerror = () => this.onError(); // Keyboard document.onkeydown = (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; if (e.code === 'Space') { e.preventDefault(); this.toggle(); } if (e.code === 'KeyM') this.toggleMute(); }; }, setupScrollDetection() { const playerSection = $('#player'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // Só mostrar se não foi fechado manualmente const shouldShow = !entry.isIntersecting && state.isPlaying && !state.miniPlayerClosed; els.miniPlayer.classList.toggle('visible', shouldShow); // Reset do estado quando volta pro player principal if (entry.isIntersecting) { state.miniPlayerClosed = false; } }); }, { threshold: 0 }); observer.observe(playerSection); }, async loadMounts() { try { console.log('[Player] Buscando mounts...'); const res = await fetch(`${CONFIG.apiBase}/get_mount_points.php?hash=${CONFIG.hash}`); const data = await res.json(); console.log('[Player] Mounts recebidos:', data); if (data.success && data.mounts && Array.isArray(data.mounts)) { state.mounts = data.mounts; console.log('[Player] Total de mounts:', state.mounts.length); const defaultIdx = state.mounts.findIndex(m => m.is_default); state.activeMountIdx = defaultIdx >= 0 ? defaultIdx : 0; state.currentMount = state.mounts[state.activeMountIdx]; if (state.mounts.length > 1) { this.renderMounts(); } } else { console.warn('[Player] Nenhum mount valido retornado'); state.currentMount = { url: CONFIG.streamUrl }; } } catch (e) { console.error('[Player] Erro ao carregar mounts:', e); state.currentMount = { url: CONFIG.streamUrl }; } }, renderMounts() { els.qualitySelector.classList.add('visible'); els.miniQualitySelector.classList.add('visible'); // Definir active index canonico baseado no mount default const defaultIdx = state.mounts.findIndex(m => m.is_default); if (state.activeMountIdx == null || state.activeMountIdx < 0 || state.activeMountIdx >= state.mounts.length) { state.activeMountIdx = defaultIdx >= 0 ? defaultIdx : 0; } state.currentMount = state.mounts[state.activeMountIdx]; const getQualityLabel = (bitrate) => { if (bitrate >= 256) return 'HD'; if (bitrate >= 192) return 'Alta'; if (bitrate >= 128) return 'Media'; return 'Eco'; }; // Ordenar (HLS no fim, depois por bitrate desc) mantendo referencia ao indice original const indexed = state.mounts.map((m, i) => ({ m, i })); indexed.sort((a, b) => { const aHls = (a.m.format === 'HLS' || a.m.is_hls) ? 1 : 0; const bHls = (b.m.format === 'HLS' || b.m.is_hls) ? 1 : 0; if (aHls !== bHls) return aHls - bHls; return (b.m.bitrate || 128) - (a.m.bitrate || 128); }); // Main selector while (els.qualitySelector.firstChild) els.qualitySelector.removeChild(els.qualitySelector.firstChild); const label = document.createElement('div'); label.className = 'quality-selector__label'; const icon = document.createElement('i'); icon.className = 'fas fa-signal'; label.appendChild(icon); label.appendChild(document.createTextNode(' Qualidade')); els.qualitySelector.appendChild(label); const options = document.createElement('div'); options.className = 'quality-selector__options'; indexed.forEach(({ m, i }) => { const isHls = (m.format === 'HLS' || m.is_hls); const bitrate = m.bitrate || 128; const format = (m.format || 'mp3').toUpperCase(); const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'quality-btn' + (i === state.activeMountIdx ? ' active' : ''); btn.dataset.idx = String(i); btn.title = m.name || (isHls ? 'HLS' : 'Stream'); const info = document.createElement('div'); info.className = 'quality-btn__info'; const br = document.createElement('span'); br.className = 'quality-btn__bitrate'; br.textContent = isHls ? 'HLS' : (bitrate + 'k'); info.appendChild(br); if (!isHls) { const meta = document.createElement('span'); meta.className = 'quality-btn__meta'; meta.textContent = format + ' ' + getQualityLabel(bitrate); info.appendChild(meta); } btn.appendChild(info); btn.addEventListener('click', () => this.selectMount(i)); options.appendChild(btn); }); els.qualitySelector.appendChild(options); // Mini selector while (els.miniQualitySelector.firstChild) els.miniQualitySelector.removeChild(els.miniQualitySelector.firstChild); indexed.forEach(({ m, i }) => { const isHls = (m.format === 'HLS' || m.is_hls); const bitrate = m.bitrate || 128; const btn = document.createElement('button'); btn.type = 'button'; btn.className = 'mini-quality-btn' + (i === state.activeMountIdx ? ' active' : ''); btn.dataset.idx = String(i); btn.title = m.name || (isHls ? 'HLS' : 'Stream'); btn.textContent = isHls ? 'HLS' : (bitrate + 'k'); btn.addEventListener('click', () => this.selectMount(i)); els.miniQualitySelector.appendChild(btn); }); }, selectMount(idx) { if (!state.mounts[idx]) return; state.activeMountIdx = idx; state.currentMount = state.mounts[idx]; this.renderMounts(); if (state.isPlaying) { this.setLoading(true); this.play(); } }, isLoading: false, isStopping: false, toggle() { if (this.isLoading) return; state.isPlaying ? this.stop() : this.play(); }, setLoading(loading) { this.isLoading = loading; if (loading) { els.playBtn.classList.add('loading'); els.miniPlayBtn.classList.add('loading'); } else { els.playBtn.classList.remove('loading'); els.miniPlayBtn.classList.remove('loading'); } }, async play() { try { const mount = state.currentMount; const url = mount?.url || CONFIG.streamUrl; if (!url) return utils.toast('Stream indisponível', 'error'); this.isStopping = false; this.setLoading(true); els.audio.volume = state.volume / 100; wsDetachHls(); if (wsIsHls(url, mount)) { // PREFERIR hls.js sobre HLS nativo: Chrome reporta canPlayType='maybe' // mas nao toca .m3u8 direto direito. So usar nativo se hls.js indisponivel. let Hls = null; try { Hls = await wsLoadHlsLib(); } catch (e) { /* hls.js falhou ao carregar */ } if (!Hls || !Hls.isSupported()) { // Fallback nativo (Safari/iOS) els.audio.src = url; await els.audio.play(); return; } { await new Promise((resolve, reject) => { _wsHls = new Hls({ enableWorker: false, // CSP bloqueia worker via blob; tambem bug conhecido com